
/*
---
script: InPlaceEditor.js
license: MIT-style license.
description: inplace editor.
copyright: Copyright (c) 2010 Akhmad Musa Hadi (Freezy)
authors: [Akhmad Musa Hadi]

requires: 
  core:1.3.1
  more:1.3.1
provides: InPlaceEditor
...
*/

/*
-----
contoh penggunaan
-----
Berikut ini contoh HTML element:
	
	...
	<tr>
		<td> Nama: </td>
		<td> <div 	id="labelNama" class="inp_label"></div> 
			 <input id="" class="inp_field" type="hidden" name="fieldNama"  />
		</td>
	</tr>
	...
	
Implementasi untuk single InPlaceEditor:
	new InPlaceEditor( $('labelNama'), $('fieldNama') );
*/
var InPlaceEditor = new Class({

		options: {
			//cell render
			cellRenderValueProperty: 'html',
			
			//cell editor
			cellEditor:	null,
			approveButton: null,
			rejectButton: null,
		},
		
		//default
		default_options:{
			cellEditor:{
				tag: 'input',
				properties: {class:'cellEditor'},
				styles:{}
			},
			approveButton:	{
				tag: 'a',
				properties: {class:'button', html:'Save'},
				styles:{}
			},
			rejectButton: 	{
				tag: 'a',
				properties: {class:'button', html:'Cancel'},
				styles:{}
			},
		},
		
		//marker
		className: 'InPlaceEditor',
		
		//event listener
		onMouseEnter: 	$empty,
		onMouseLeave: 	$empty,
//		onFocus: 		$empty,
		onClick: 		$empty,

		cellRenderEvents: null,
		
		Implements: [Events, Options],
		
		/**
		 * el (element) - cell render, untuk render value (label)
		 * target_input - hidden input, untuk menyimpan nilai saat editing
		 * options (object) - options
		 */
		initialize: function(el, targetInput, options) {
			this.setOptions(options);
			el.each(function(element, index){
				this.attach(element, targetInput[index]);
			}.bind(this));
		},
		
		attach: function (el, targetInput) {
			//prevent double attachment
			if (el.retrieve(this.className)) return this;
			
			el.store(this.className, true);
			el.store(this.className+'.targetInput', targetInput);
			
			el.retrieve(this.className+'.cellRender_display', el.getStyle('display'));
			
			//install events
			this.cellRenderEvents = this.getEvents(el);
			el.addEvents(this.cellRenderEvents);
			
			return this;
		},
		
		detach: function (el) {
			el.removeEvents(this.cellRender.events);
			return this;
		},
		
		getEvents: function(el){
			return {
				click: function(){
					this.build(el);
					this.onClick(this, el);
				}.bind(this),
				mouseenter: function(){
					this.onMouseEnter(this, el);
				}.bind(this),
				mouseleave: function(){
					this.onMouseLeave(this, el);
				}.bind(this)
			};
		},

		build: function (el) {
			//check if cellEditor is already shown
			if (el.retrieve(this.className+'.showCellEditor')) return;
			el.setStyle('display', 'none');
			
			var self = this;
			var opt = this.options;
			var approveFunc = function(){
				el.retrieve(self.className+'.targetInput').value = editor.value;
				el.set(opt.cellRenderValueProperty,editor.value);
				el.setStyle('display', el.retrieve(this.className+'.cellRender_display'));
				this.getParent('.inPlaceEditor').destroy();
				el.eliminate(self.className+'.showCellEditor');
			};
			var rejectFunc = function(){
				el.setStyle('display', el.retrieve(this.className+'.cellRender_display'));
				this.getParent('.inPlaceEditor').destroy();
				el.eliminate(self.className+'.showCellEditor');
			}
			
			
			// get label value
			var oldValue = el.get(opt.cellRenderValueProperty);
			
			//create container
			var container =  new Element('span',{class:"inPlaceEditor"}).inject(el,'after');
			
			//create the cell editor
			var editor = this._createElement($merge(opt.cellEditor,this.default_options.cellEditor))
				.inject(container);
			editor.set('value',oldValue)
				.addEvent('keydown',function(event){
					if (event.key == 'enter') approveFunc();
					else if (event.key == 'esc') rejectFunc();
				})
				.focus();
			
			//create reject button
			var reject = this._createElement($merge(opt.rejectButton,this.default_options.rejectButton))
				.inject(container)
				.addEvents({
					click: rejectFunc
				});
			
			//create approve button
			var approve = this._createElement($merge(opt.approveButton,this.default_options.approveButton))
				.inject(container)
				.addEvents({
					click: approveFunc
				});
			
			//marker
			el.store(this.className+'.showCellEditor', true);	//mark cellEditor shown
			return this;
		},

		_createElement: function(opt){
			return new Element(opt.tag, opt.properties)
				.setStyles(opt.styles)
				.addEvents(opt.events);
		}
});